"""
剪映草稿项目解析服务

负责解析剪映草稿项目模板，并创建新的草稿项目。
"""

import json
import shutil
import uuid
from pathlib import Path
from typing import Dict, List, Any, Optional
from datetime import datetime

from loguru import logger
from src.core.di import Service


@Service("jianying_draft_service")
class JianyingDraftService:
    """
    剪映草稿项目解析服务
    
    功能：
    1. 解析指定目录下的所有剪映草稿项目模板
    2. 解析模板项目中的关键文件
    3. 基于模板创建新的草稿项目
    """

    def __init__(self):
        self.logger = logger.bind(component="JianyingDraftService")

    async def scan_template_projects(self, templates_dir: str) -> List[Dict[str, Any]]:
        """
        扫描指定目录下的所有剪映草稿项目模板
        
        Args:
            templates_dir: 模板目录路径
            
        Returns:
            模板项目列表
        """
        templates_path = Path(templates_dir)
        
        if not templates_path.exists():
            self.logger.error(f"模板目录不存在: {templates_dir}")
            return []
        
        if not templates_path.is_dir():
            self.logger.error(f"路径不是目录: {templates_dir}")
            return []
        
        templates = []
        
        # 遍历所有子文件夹
        for project_dir in templates_path.iterdir():
            if not project_dir.is_dir():
                continue
            
            try:
                template_info = await self._parse_template_project(project_dir)
                if template_info:
                    templates.append(template_info)
                    self.logger.info(f"✅ 成功解析模板项目: {project_dir.name}")
                else:
                    self.logger.warning(f"⚠️ 跳过无效模板项目: {project_dir.name}")
            except Exception as e:
                self.logger.error(f"❌ 解析模板项目失败 {project_dir.name}: {e}")
        
        self.logger.info(f"📊 扫描完成，找到 {len(templates)} 个有效模板项目")
        return templates

    async def _parse_template_project(self, project_dir: Path) -> Optional[Dict[str, Any]]:
        """
        解析单个模板项目
        
        Args:
            project_dir: 项目目录路径
            
        Returns:
            模板项目信息，如果解析失败返回None
        """
        # 检查必需的文件
        required_files = [
            "draft_content.json",
            "draft_meta_info.json", 
            "draft_virtual_store.json"
        ]
        
        missing_files = []
        for file_name in required_files:
            file_path = project_dir / file_name
            if not file_path.exists():
                missing_files.append(file_name)
        
        if missing_files:
            self.logger.warning(f"模板项目缺少必需文件: {project_dir.name} - {missing_files}")
            return None
        
        try:
            # 解析各个文件
            draft_content = self._load_json_file(project_dir / "draft_content.json")
            draft_meta_info = self._load_json_file(project_dir / "draft_meta_info.json")
            draft_virtual_store = self._load_json_file(project_dir / "draft_virtual_store.json")
            
            # 提取详细的模板信息
            detailed_info = self._extract_detailed_template_info(draft_content, draft_meta_info)

            # 计算素材数量（从虚拟存储中获取更准确的数量）
            virtual_store = draft_virtual_store.get("draft_virtual_store", [])
            materials_count = 0
            for store_group in virtual_store:
                if store_group.get("type") == 1:  # 素材引用类型
                    materials_count = len(store_group.get("value", []))
                    break

            # 组合模板信息
            template_info = {
                "template_id": project_dir.name,
                "template_path": str(project_dir),
                "template_name": draft_meta_info.get("draft_name", project_dir.name),
                "template_description": detailed_info["description"],
                "creation_time": self._safe_timestamp_to_seconds(draft_meta_info.get("tm_draft_create", 0)),
                "modification_time": self._safe_timestamp_to_seconds(draft_meta_info.get("tm_draft_modify", 0)),
                "duration": draft_content.get("duration", 0),
                "duration_seconds": detailed_info["duration_seconds"],
                "canvas_config": draft_content.get("canvas_config", {}),
                "canvas_info": detailed_info["canvas"],
                "tracks_count": len(draft_content.get("tracks", [])),
                "tracks_info": detailed_info["tracks"],
                "materials_count": materials_count,
                "materials_info": detailed_info["materials"],
                "imported_materials_info": detailed_info["imported_materials"],
                "effects_info": detailed_info["effects"],
                "project_id": detailed_info["project_id"],
                "fps": detailed_info["fps"],
                "draft_content": draft_content,
                "draft_meta_info": draft_meta_info,
                "draft_virtual_store": draft_virtual_store,
                "parsed_at": datetime.now().isoformat()
            }
            
            return template_info
            
        except Exception as e:
            self.logger.error(f"解析模板项目文件失败 {project_dir.name}: {e}")
            return None

    def _load_json_file(self, file_path: Path) -> Dict[str, Any]:
        """
        加载JSON文件
        
        Args:
            file_path: 文件路径
            
        Returns:
            JSON数据
        """
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except json.JSONDecodeError as e:
            self.logger.error(f"JSON解析失败 {file_path}: {e}")
            raise
        except Exception as e:
            self.logger.error(f"文件读取失败 {file_path}: {e}")
            raise

    def _safe_timestamp_to_seconds(self, timestamp: Any) -> int:
        """
        安全地将时间戳转换为秒级时间戳

        Args:
            timestamp: 时间戳（可能是秒、毫秒或其他格式）

        Returns:
            秒级时间戳，如果无法转换则返回0
        """
        try:
            if not timestamp:
                return 0

            timestamp = int(timestamp)

            # 判断时间戳格式
            if timestamp > 1e12:  # 毫秒时间戳 (> 2001年)
                return int(timestamp / 1000)
            elif timestamp > 1e9:  # 秒时间戳 (> 2001年)
                return timestamp
            elif timestamp > 1e6:  # 可能是微秒时间戳
                return int(timestamp / 1000000)
            else:
                # 时间戳太小，可能是相对时间或其他格式
                return 0

        except (ValueError, TypeError):
            return 0

    def _extract_detailed_template_info(self, draft_content: Dict[str, Any], draft_meta_info: Dict[str, Any]) -> Dict[str, Any]:
        """
        提取详细的模板信息

        Args:
            draft_content: 草稿内容
            draft_meta_info: 草稿元信息

        Returns:
            详细信息字典
        """
        info = {}

        # 基本信息
        info["project_id"] = draft_content.get("id", "")
        info["fps"] = draft_content.get("fps", 30.0)
        info["duration_seconds"] = draft_content.get("duration", 0) / 1000000

        # 画布配置
        canvas_config = draft_content.get("canvas_config", {})
        info["canvas"] = {
            "width": canvas_config.get("width", 0),
            "height": canvas_config.get("height", 0),
            "ratio": canvas_config.get("ratio", "unknown"),
            "aspect_ratio": self._calculate_aspect_ratio(canvas_config)
        }

        # 轨道分析
        tracks = draft_content.get("tracks", [])
        info["tracks"] = {
            "total": len(tracks),
            "video_tracks": len([t for t in tracks if t.get("type") == "video"]),
            "audio_tracks": len([t for t in tracks if t.get("type") == "audio"]),
            "details": self._analyze_tracks(tracks)
        }

        # 素材分析
        materials = draft_content.get("materials", {})
        info["materials"] = self._analyze_materials(materials)

        # 从元信息中提取素材详情
        meta_materials = draft_meta_info.get("draft_materials", [])
        info["imported_materials"] = self._analyze_meta_materials(meta_materials)

        # 特效和动画
        info["effects"] = {
            "video_effects": len(materials.get("effects", [])),
            "transitions": len(materials.get("transitions", [])),
            "animations": len(materials.get("material_animations", [])),
            "filters": len(materials.get("filters", [])),
            "stickers": len(materials.get("stickers", []))
        }

        # 生成描述
        info["description"] = self._generate_template_description(info)

        return info

    def _calculate_aspect_ratio(self, canvas_config: Dict[str, Any]) -> str:
        """计算宽高比"""
        width = canvas_config.get("width", 0)
        height = canvas_config.get("height", 0)

        if width and height:
            # 计算最大公约数
            def gcd(a, b):
                while b:
                    a, b = b, a % b
                return a

            g = gcd(width, height)
            ratio_w = width // g
            ratio_h = height // g

            # 常见比例的识别
            common_ratios = {
                (16, 9): "16:9",
                (9, 16): "9:16",
                (4, 3): "4:3",
                (3, 4): "3:4",
                (1, 1): "1:1",
                (21, 9): "21:9"
            }

            return common_ratios.get((ratio_w, ratio_h), f"{ratio_w}:{ratio_h}")

        return "unknown"

    def _analyze_tracks(self, tracks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """分析轨道详情"""
        track_details = []

        for i, track in enumerate(tracks):
            track_type = track.get("type", "unknown")
            segments = track.get("segments", [])

            track_info = {
                "index": i + 1,
                "type": track_type,
                "segments_count": len(segments),
                "total_duration": 0,
                "segments": []
            }

            for segment in segments:
                target_timerange = segment.get("target_timerange", {})
                duration = target_timerange.get("duration", 0) / 1000000
                start = target_timerange.get("start", 0) / 1000000

                track_info["total_duration"] += duration
                track_info["segments"].append({
                    "start": start,
                    "duration": duration,
                    "end": start + duration,
                    "material_id": segment.get("material_id", "")[:8] + "..."
                })

            track_details.append(track_info)

        return track_details

    def _analyze_materials(self, materials: Dict[str, Any]) -> Dict[str, Any]:
        """分析素材详情"""
        material_info = {}

        # 视频素材
        videos = materials.get("videos", [])
        material_info["videos"] = {
            "count": len(videos),
            "details": []
        }

        for video in videos[:5]:  # 只分析前5个
            material_info["videos"]["details"].append({
                "name": video.get("material_name", "unknown"),
                "duration": video.get("duration", 0) / 1000000,
                "width": video.get("width", 0),
                "height": video.get("height", 0),
                "has_audio": video.get("has_audio", False),
                "path": video.get("path", "")
            })

        # 音频素材
        audios = materials.get("audios", [])
        material_info["audios"] = {
            "count": len(audios),
            "details": []
        }

        for audio in audios[:3]:  # 只分析前3个
            material_info["audios"]["details"].append({
                "name": audio.get("name", "unknown"),
                "duration": audio.get("duration", 0) / 1000000,
                "path": audio.get("path", "")
            })

        # 其他素材类型
        material_info["texts"] = {"count": len(materials.get("texts", []))}
        material_info["images"] = {"count": len(materials.get("images", []))}
        material_info["stickers"] = {"count": len(materials.get("stickers", []))}

        return material_info

    def _analyze_meta_materials(self, meta_materials: List[Dict[str, Any]]) -> Dict[str, Any]:
        """分析元信息中的素材"""
        imported_info = {}

        type_names = {
            0: "videos",
            1: "audios",
            2: "images",
            3: "texts",
            6: "stickers",
            7: "effects",
            8: "others"
        }

        for material_group in meta_materials:
            material_type = material_group.get("type", -1)
            material_list = material_group.get("value", [])
            type_name = type_names.get(material_type, f"type_{material_type}")

            imported_info[type_name] = {
                "count": len(material_list),
                "details": []
            }

            # 详细分析视频素材
            if material_type == 0 and material_list:  # 视频
                for material in material_list[:3]:  # 只分析前3个
                    imported_info[type_name]["details"].append({
                        "name": material.get("extra_info", "unknown"),
                        "duration": material.get("duration", 0) / 1000000,
                        "width": material.get("width", 0),
                        "height": material.get("height", 0),
                        "path": material.get("file_Path", ""),
                        "id": material.get("id", "")
                    })

        return imported_info

    def _generate_template_description(self, info: Dict[str, Any]) -> str:
        """生成模板描述"""
        description_parts = []

        # 画布信息
        canvas = info.get("canvas", {})
        if canvas.get("ratio") != "unknown":
            description_parts.append(f"画布: {canvas['ratio']}")

        # 轨道信息
        tracks = info.get("tracks", {})
        if tracks.get("total", 0) > 0:
            track_desc = f"{tracks['total']}轨道"
            if tracks.get("video_tracks", 0) > 0:
                track_desc += f"({tracks['video_tracks']}视频"
                if tracks.get("audio_tracks", 0) > 0:
                    track_desc += f"+{tracks['audio_tracks']}音频)"
                else:
                    track_desc += ")"
            description_parts.append(track_desc)

        # 素材信息
        materials = info.get("materials", {})
        video_count = materials.get("videos", {}).get("count", 0)
        audio_count = materials.get("audios", {}).get("count", 0)

        if video_count > 0:
            description_parts.append(f"{video_count}个视频")
        if audio_count > 0:
            description_parts.append(f"{audio_count}个音频")

        # 特效信息
        effects = info.get("effects", {})
        effect_count = effects.get("video_effects", 0)
        transition_count = effects.get("transitions", 0)

        if effect_count > 0:
            description_parts.append(f"{effect_count}个特效")
        if transition_count > 0:
            description_parts.append(f"{transition_count}个转场")

        # 时长信息
        duration = info.get("duration_seconds", 0)
        if duration > 0:
            description_parts.append(f"{duration:.1f}秒")

        return " | ".join(description_parts) if description_parts else "剪映草稿项目模板"

    async def create_draft_from_template(self, 
                                       template_info: Dict[str, Any], 
                                       target_dir: str,
                                       project_name: Optional[str] = None,
                                       custom_materials: Optional[List[str]] = None) -> Dict[str, Any]:
        """
        基于模板创建新的草稿项目
        
        Args:
            template_info: 模板信息
            target_dir: 目标目录
            project_name: 项目名称（可选）
            custom_materials: 自定义素材路径列表（可选）
            
        Returns:
            创建结果信息
        """
        try:
            # 生成新项目ID和名称
            new_project_id = str(uuid.uuid4()).replace('-', '')
            if not project_name:
                project_name = f"{template_info['template_name']}_copy_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
            
            # 创建目标目录
            target_path = Path(target_dir) / new_project_id
            target_path.mkdir(parents=True, exist_ok=True)
            
            # 复制并修改草稿文件
            new_draft_content = await self._modify_draft_content(
                template_info["draft_content"], 
                new_project_id,
                custom_materials
            )
            
            new_draft_meta_info = await self._modify_draft_meta_info(
                template_info["draft_meta_info"],
                new_project_id,
                project_name
            )
            
            new_draft_virtual_store = await self._modify_draft_virtual_store(
                template_info["draft_virtual_store"],
                custom_materials
            )
            
            # 保存新的草稿文件
            self._save_json_file(target_path / "draft_content.json", new_draft_content)
            self._save_json_file(target_path / "draft_meta_info.json", new_draft_meta_info)
            self._save_json_file(target_path / "draft_virtual_store.json", new_draft_virtual_store)
            
            # 复制其他文件（如果存在）
            template_path = Path(template_info["template_path"])
            for file_path in template_path.iterdir():
                if file_path.is_file() and file_path.suffix not in ['.json']:
                    target_file = target_path / file_path.name
                    shutil.copy2(file_path, target_file)
            
            result = {
                "success": True,
                "project_id": new_project_id,
                "project_name": project_name,
                "project_path": str(target_path),
                "template_id": template_info["template_id"],
                "created_at": datetime.now().isoformat(),
                "files_created": [
                    "draft_content.json",
                    "draft_meta_info.json", 
                    "draft_virtual_store.json"
                ]
            }
            
            self.logger.info(f"✅ 成功创建草稿项目: {project_name} -> {target_path}")
            return result
            
        except Exception as e:
            self.logger.error(f"❌ 创建草稿项目失败: {e}")
            return {
                "success": False,
                "error": str(e),
                "template_id": template_info.get("template_id", "unknown")
            }

    async def _modify_draft_content(self, 
                                  original_content: Dict[str, Any], 
                                  new_project_id: str,
                                  custom_materials: Optional[List[str]] = None) -> Dict[str, Any]:
        """
        修改草稿内容，更新项目ID和素材路径
        
        Args:
            original_content: 原始草稿内容
            new_project_id: 新项目ID
            custom_materials: 自定义素材路径列表
            
        Returns:
            修改后的草稿内容
        """
        # 深拷贝原始内容
        new_content = json.loads(json.dumps(original_content))
        
        # 更新项目ID相关字段
        if "id" in new_content:
            new_content["id"] = new_project_id
        
        # 如果提供了自定义素材，更新素材路径
        if custom_materials:
            await self._update_material_paths(new_content, custom_materials)
        
        return new_content

    async def _modify_draft_meta_info(self, 
                                    original_meta: Dict[str, Any], 
                                    new_project_id: str,
                                    project_name: str) -> Dict[str, Any]:
        """
        修改草稿元信息
        
        Args:
            original_meta: 原始元信息
            new_project_id: 新项目ID
            project_name: 项目名称
            
        Returns:
            修改后的元信息
        """
        new_meta = json.loads(json.dumps(original_meta))
        
        # 更新基本信息
        current_time = int(datetime.now().timestamp() * 1000)
        new_meta.update({
            "draft_id": new_project_id,
            "draft_name": project_name,
            "tm_draft_create": current_time,
            "tm_draft_modify": current_time
        })
        
        return new_meta

    async def _modify_draft_virtual_store(self, 
                                        original_store: Dict[str, Any],
                                        custom_materials: Optional[List[str]] = None) -> Dict[str, Any]:
        """
        修改虚拟存储信息
        
        Args:
            original_store: 原始虚拟存储
            custom_materials: 自定义素材路径列表
            
        Returns:
            修改后的虚拟存储
        """
        new_store = json.loads(json.dumps(original_store))
        
        # 如果提供了自定义素材，更新素材库
        if custom_materials:
            await self._update_virtual_materials(new_store, custom_materials)
        
        return new_store

    async def _update_material_paths(self, content: Dict[str, Any], custom_materials: List[str]):
        """
        更新内容中的素材路径
        
        Args:
            content: 草稿内容
            custom_materials: 自定义素材路径列表
        """
        # 这里需要根据剪映的具体数据结构来实现
        # 通常需要遍历tracks中的segments，更新素材路径
        tracks = content.get("tracks", [])
        material_index = 0
        
        for track in tracks:
            segments = track.get("segments", [])
            for segment in segments:
                if segment.get("material_type") in ["video", "audio", "image"]:
                    if material_index < len(custom_materials):
                        # 更新素材路径
                        if "material_path" in segment:
                            segment["material_path"] = custom_materials[material_index]
                        material_index += 1

    async def _update_virtual_materials(self, store: Dict[str, Any], custom_materials: List[str]):
        """
        更新虚拟存储中的素材信息
        
        Args:
            store: 虚拟存储
            custom_materials: 自定义素材路径列表
        """
        # 更新materials列表
        materials = store.get("materials", [])
        for i, material_path in enumerate(custom_materials):
            if i < len(materials):
                material = materials[i]
                # 更新素材路径和相关信息
                material["path"] = material_path
                material["file_name"] = Path(material_path).name

    def _save_json_file(self, file_path: Path, data: Dict[str, Any]):
        """
        保存JSON文件
        
        Args:
            file_path: 文件路径
            data: 要保存的数据
        """
        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            self.logger.error(f"保存JSON文件失败 {file_path}: {e}")
            raise

    async def get_template_info(self, template_id: str, templates_dir: str) -> Optional[Dict[str, Any]]:
        """
        获取指定模板的详细信息
        
        Args:
            template_id: 模板ID
            templates_dir: 模板目录
            
        Returns:
            模板信息，如果不存在返回None
        """
        template_path = Path(templates_dir) / template_id
        if not template_path.exists():
            return None
        
        return await self._parse_template_project(template_path)

    async def list_template_summaries(self, templates_dir: str) -> List[Dict[str, Any]]:
        """
        获取所有模板的摘要信息
        
        Args:
            templates_dir: 模板目录
            
        Returns:
            模板摘要列表
        """
        templates = await self.scan_template_projects(templates_dir)
        
        summaries = []
        for template in templates:
            summary = {
                "template_id": template["template_id"],
                "template_name": template["template_name"],
                "description": template["template_description"],
                "duration": template["duration"],
                "tracks_count": template["tracks_count"],
                "materials_count": template["materials_count"],
                "creation_time": template["creation_time"]
            }
            summaries.append(summary)
        
        return summaries
